package com.fr.chicken.manager.verifcode;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public abstract  class AbstractVerifyCode<KEY> implements IVerifyCode<KEY>{

    private Map<KEY, VarcharCode> verifyCodes = new ConcurrentHashMap<KEY, VarcharCode>();

    /**
     * 验证码有效时间
     * */
    private long verifyCodeValidTime;

    /**
     * 验证码有效时间的单位
     * */
    private TimeUnit verifyCodeValidTimeUnit;

    public AbstractVerifyCode(long verifyCodeValidTime, TimeUnit verifyCodeValidTimeUnit){
        this.verifyCodeValidTime = verifyCodeValidTime;
        this.verifyCodeValidTimeUnit = verifyCodeValidTimeUnit;
    }

    /**
     * 创建一个验证码
     *  如果已存在一个有效的验证码 直接返回
     * */
    @Override
    public String createVerifyCode(KEY key) {
        VarcharCode varcharCode = getValidVerifyCode(key);
        if(varcharCode == null){
            varcharCode = createAndSaveVerifyCode(key);
        }
        return varcharCode.getVerifyCode();
    }

    @Override
    public boolean verify(KEY key, String code) {
        VarcharCode varcharCode = getValidVerifyCode(key);
        System.out.println(code);
        System.out.println(varcharCode.getVerifyCode());
        if(varcharCode != null){
            return varcharCode.getVerifyCode().equals(code);
        }
        return false;
    }

    @Override
    public void removeVerifyCode(KEY key) {
        synchronized (verifyCodes){
            verifyCodes.remove(key);
        }
    }

    /**
     * 获取一个有效的验证码
     * */
    private VarcharCode getValidVerifyCode(KEY key){
        synchronized (verifyCodes){
            if(!verifyCodes.containsKey(key)){
                return null;
            }
        }
        VarcharCode varcharCode = verifyCodes.get(key);
        if(!varcharCode.valid(verifyCodeValidTime,verifyCodeValidTimeUnit)){
            return null;
        }
        return varcharCode;
    }


    protected VarcharCode createAndSaveVerifyCode(KEY key){
        VarcharCode result = new VarcharCode(createVerifyCodeStr(),System.currentTimeMillis());
        synchronized (verifyCodes){
            VarcharCode oldVarcharCode =  verifyCodes.put(key,result);
            if(oldVarcharCode != null && oldVarcharCode.valid(verifyCodeValidTime,verifyCodeValidTimeUnit)){
                throw new IllegalArgumentException("Verify Code not TimeOut");
            }
        }
        return result;
    }

    protected abstract String createVerifyCodeStr();
}
